package com.sleepless.my.utils;
import com.sleepless.my.repository.UsersRepository;
import io.jsonwebtoken.*;
import io.jsonwebtoken.security.Keys;
import io.jsonwebtoken.security.SecureDigestAlgorithm;
import com.sleepless.my.entity.UsersEntity;
import jakarta.annotation.PostConstruct;
import jakarta.annotation.Resource;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

import javax.crypto.SecretKey;
import java.util.*;

@Data
@Component
@Slf4j
@ConfigurationProperties(prefix = "jwt")
public class JwtUtil {

    private static String header;
    private static long expire;
    private static String secret;
    private static String issuer;

    @Resource
    private UsersRepository usersRespository;

    private String Header;
    private long Expire;
    private String Secret;
    private String Issuer;

    private static UsersRepository staticRepo;

    @PostConstruct
    public void init() {
        JwtUtil.staticRepo = usersRespository;
        header = Header;
        expire = Expire;
        secret = Secret;
        issuer = Issuer;
    }

    private static final HashSet<String> blackList = new HashSet<>();

    public static Map<String, Object> createClaims(String userName) {
        Map<String, Object> claims = new HashMap<>();
        claims.put("username", userName);
        return claims;
    }

    /**
     * 生成jwt
     * 使用Hs256算法，私钥使用固定密钥
     *
     * @param claims 设置的信息
     * @return
     */
    public static String createJWT(Map<String, Object> claims) {
        //指定加密算法
        SecureDigestAlgorithm<SecretKey, SecretKey> algorithm = Jwts.SIG.HS256;
        //生成JWT的时间
        long expMillis = System.currentTimeMillis() + expire;
        Date exp = new Date(expMillis);
        //密钥实例
        SecretKey key = Keys.hmacShaKeyFor(secret.getBytes());

        return Jwts.builder()
                .signWith(key, algorithm) //设置签名使用的签名算法和签名使用的秘钥
                //如果有私有声明，一点要先设置这个自己创建的私有的声明，这个是给builder的claims赋值，一旦卸载标准的声明赋值之后，就是覆盖了那些标准的声明的
                .expiration(exp)
                .claims(claims) //设置自定义负载信息
                .issuer(issuer)
                .compact();
    }


    /**
     * 解析jwt
     *
     * @param token
     * @return
     */
    public static Jws<Claims> parseJWT(String token) {
        //密钥实例
        SecretKey key = Keys.hmacShaKeyFor(secret.getBytes());

        return Jwts.parser()
                .verifyWith(key)  //设置签名的密钥
                .build()
                .parseSignedClaims(token);
    }


    /**
     * 获取合法claims
     *
     * @param token
     * @return
     */
    public static Claims getClaims(String token) {
        Claims claims = parseJWT(token).getPayload();
        if (claims == null || isTokenExpired(claims)) {
            return null;
        }
        return claims;
    }

    public static String getUserName(String token) {
        Claims claims = getClaims(token);
        if (claims != null) {
            return claims.get("username", String.class);
        }
        return null;
    }

    /**
     * 获取User
     *
     * @param token
     * @return
     */
    public static UsersEntity getUser(String token) {
        Claims claims = getClaims(token);
        if (claims != null) {
            UsersEntity user = staticRepo.findByusername(claims.get("username", String.class));
            if (user != null) {
                return user;
            }
        }
        return null;
    }

    /**
     * 判断token是否过期
     *
     * @param claims
     * @return
     */
    public static boolean isTokenExpired(Claims claims) {
        return claims.getExpiration().before(new Date());
    }
}
